package xyz.bmj.view;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import com.sun.media.jfxmedia.logging.Logger;
import javafx.application.Platform;
import javafx.beans.binding.When;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.event.ActionEvent;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.util.Duration;
import lombok.extern.slf4j.Slf4j;
import org.pomo.toasterfx.ToastBarToasterService;
import org.pomo.toasterfx.model.ToastParameter;
import org.pomo.toasterfx.model.impl.ToastTypes;
import xyz.bmj.hotkey.HotKey;
import xyz.bmj.model.BResourceResponse;
import xyz.bmj.model.HotKeySetting;
import xyz.bmj.model.MlUrl;
import xyz.bmj.spider.Spider;
import xyz.bmj.util.Constant;
import xyz.bmj.util.PlayModel;

import java.io.File;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;

import static xyz.bmj.sensitivity.Constant.PROXY_URL;

@Slf4j
public class Controller implements Initializable {


    public VBox layout;
    public MediaView mv;
    public Button playBtn;
    public TableView<BResourceResponse.DataBean.MediasBean> mTable;
    public Button prevBtn;
    public Button nextBtn;
    public Slider volumeSlider;
    public Slider progressSlider;
    public ChoiceBox<PlayModel> playModelChoice;
    public TextField searchField;
    public Button refreshBtn;

    private MediaPlayer player;
    private final Spider spider = new Spider();
    private BResourceResponse.DataBean.MediasBean selectedMedia;
    private int listIndex = 0;
    private boolean onPressMouse = false;
    private final List<Integer> randomIndex = new LinkedList<>();
    private PlayModel selectPlayModel = PlayModel.LOOP;
    private final BooleanProperty playing = new SimpleBooleanProperty(false);
    private ObservableList<BResourceResponse.DataBean.MediasBean> m;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        playBtn.textProperty().bind(new When(playing).then("暂停").otherwise("播放"));

        Logger.setLevel(Logger.DEBUG);
        playModelChoice.setItems(FXCollections.observableArrayList(PlayModel.LOOP, PlayModel.ONE, PlayModel.RANDOM));
        playModelChoice.setValue(PlayModel.LOOP);
        playModelChoice.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            selectPlayModel = newValue;
            if (newValue == PlayModel.RANDOM) {
                initRandom();
            }
        });
        TableColumn<BResourceResponse.DataBean.MediasBean, String> titleCol = new TableColumn<>("title");
        titleCol.setCellValueFactory(new PropertyValueFactory<>("title"));
        TableColumn<BResourceResponse.DataBean.MediasBean, String> upperCol = new TableColumn<>("upper");
        upperCol.setCellValueFactory(new PropertyValueFactory<>("upper"));
        mTable.getColumns().addAll(titleCol, upperCol);
        loadList();


        // 右键菜单===================================================================
        // 创建右键菜单
        ContextMenu contextMenu = new ContextMenu();
        MenuItem downloadItem = new MenuItem("download");
        downloadItem.setOnAction(actionEvent -> {
//            String autoUrl = spider.audioUrl(Constant.URL_BASE + selectedMedia.getBv_id());
            spider.downLoad(selectedMedia.getTitle(), selectedMedia.getBv_id());
        });
        contextMenu.getItems().addAll(downloadItem);

        mTable.setRowFactory(mediasBeanTableView -> {
            TableRow<BResourceResponse.DataBean.MediasBean> row = new TableRow<>();
            row.setOnMouseClicked(mouseEvent -> {
                selectedMedia = row.getItem();
                if (mouseEvent.getClickCount() == 2) {
                    listIndex = row.getIndex();
                    play();
                    initRandom();
                }
            });
            row.setContextMenu(contextMenu);
            return row;
        });

        progressSlider.setOnMousePressed(event -> {
            onPressMouse = true;
        });
        progressSlider.setOnMouseReleased(event -> {
            onPressMouse = false;
            System.out.println("start time:" + player.getStartTime().toSeconds());
            System.out.println("stop time:" + player.getStopTime().toSeconds());
//            System.out.println("stop time:" + player.get);
            System.out.println("seek time:" + progressSlider.getValue());
            System.out.println(player.getStatus());
            System.out.println(player.getCurrentTime().toSeconds());
            System.out.println(player.getTotalDuration().toSeconds());
            System.out.println(player.getBufferProgressTime().toSeconds());
            new Thread(() -> player.seek(Duration.seconds(progressSlider.getValue()))).start();
        });

        initHotKey();
        search();

    }

    public void downloadAll() {
        System.out.println("下载全部");
        log.info("list size{}", m.size());
        FileUtil.appendUtf8String(m.size() + "\n", FileUtil.newFile(Constant.BASE_PATH + "log" + File.separator + "download.log"));
        ExecutorService nt = ThreadUtil.newExecutor(10);
        final int[] mm = {1};
        for (int i = 0; i < m.size(); i++) {
            BResourceResponse.DataBean.MediasBean mb = m.get(i);
            FileUtil.appendUtf8String(String.format("正在下载第%s首,共%s首，名称%s", i + 1, m.size(), mb.getTitle()) + "\n", FileUtil.newFile(Constant.BASE_PATH + "log" + File.separator + "download.log"));
            log.info("正在下载第{}首,共{}首，名称{}", i + 1, m.size(), mb.getTitle());
            int finalI = i;
            nt.submit(() -> {
                //ThreadUtil.execute(() -> {
                int num = ((ThreadPoolExecutor) nt).getActiveCount();
                FileUtil.appendUtf8String(String.format("线程数%s", num) + "\n", FileUtil.newFile(Constant.BASE_PATH + "log" + File.separator + "download.log"));
                FileUtil.appendUtf8String(String.format("正在下载第%s首,共%s首，名称%s", finalI + 1, m.size(), mb.getTitle()) + "\n", FileUtil.newFile(Constant.BASE_PATH + "log" + File.separator + "download.log"));
                spider.downLoad(mb.getTitle(), mb.getBv_id());
                FileUtil.appendUtf8String(String.format("完成下载第%s首,共%s首，名称%s", mm[0]++, m.size(), mb.getTitle()) + "\n", FileUtil.newFile(Constant.BASE_PATH + "log" + File.separator + "download.log"));
                //});
            });

        }

    }


    private void loadList() {
        ThreadUtil.execAsync(() -> {
            List<BResourceResponse.DataBean.MediasBean> l = spider.mediaListAllItem(new MlUrl());

            ObservableList<BResourceResponse.DataBean.MediasBean> m = FXCollections.observableArrayList();
            m.addAll(l);
            this.m = m;
            mTable.setItems(m);
        });
    }


    //        搜索
    private void search() {
        searchField.textProperty().addListener((observableValue, s, t1) -> {
            FilteredList<BResourceResponse.DataBean.MediasBean> r1 = this.m.filtered(mediasBean -> mediasBean.getTitle().contains(t1));
            mTable.setItems(r1);
        });
    }

    private void toast() {
        ToastBarToasterService service = new ToastBarToasterService();
        service.initialize();
        ToastParameter parameter = ToastParameter.builder()
                .timeout(Duration.seconds(5))
                .build();

        service.bomb(mTable.getItems().get(listIndex).getTitle()
                , mTable.getItems().get(listIndex).getUpper().getName()
                , parameter, ToastTypes.INFO);
    }

    public void initHotKey() {
        HotKey hk = HotKey.getInstance();
        HotKeySetting hks = MainView.hks;
        hk.setKey(this::toast, hks.getToast().masterKey, hks.getToast().markKey);
        hk.setKey(() -> playMedia(null), 57378, 0);
        hk.setKey(() -> playMedia(null), hks.getPlay().masterKey, hks.getPlay().markKey);
        hk.setKey(() -> nextMedia(null), 57369, 0);
        hk.setKey(() -> nextMedia(null), hks.getNextMusic().masterKey, hks.getNextMusic().markKey);
        hk.setKey(() -> prevMedia(null), 57360, 0);
        hk.setKey(() -> prevMedia(null), hks.getPrevMusic().masterKey, hks.getPrevMusic().markKey);
        hk.setKey(() -> {
            double v = volumeSlider.getValue();
            if (v < 100) {
                volumeSlider.valueProperty().set(v + 10);
            } else if (v + 100 > volumeSlider.maxProperty().get()) {
                volumeSlider.valueProperty().set(volumeSlider.maxProperty().doubleValue());
            } else {
                volumeSlider.valueProperty().set(v + 100);
            }
        }, hks.getVolumeUp().masterKey, hks.getVolumeUp().markKey);
        hk.setKey(() -> {

            double v = volumeSlider.getValue();
            if (v - 100 < 0 && v - 10 > 100) {
                volumeSlider.valueProperty().set(0);
            } else if (v - 10 < 100) {
                volumeSlider.valueProperty().set(v - 10);

            } else {
                volumeSlider.valueProperty().set(v - 100);
            }

        }, hks.getVolumeDown().masterKey, hks.getVolumeDown().markKey);
    }


    private void initRandom() {
        if (selectPlayModel == PlayModel.RANDOM) {
            randomIndex.clear();
//            randomIndex.add(listIndex);
            System.out.println(mTable.getItems().size());
            int[] randoms = NumberUtil.generateRandomNumber(0, mTable.getItems().size(), mTable.getItems().size());
            for (int rd : randoms) {
                if (rd != listIndex) {
                    randomIndex.add(rd);
                }
            }
        }
    }

    private void play() {
        toast();
        Platform.runLater(() -> mTable.scrollTo(listIndex));
        if (this.player != null) {
            this.player.dispose();
        }
//        选中正在播放的行
        mTable.getSelectionModel().select(listIndex);
        String autoUrl = spider.audioUrl(Constant.URL_BASE + mTable.getItems().get(listIndex).getBv_id());
        //Media media = new Media(new File("E:\\code\\b_music_j\\target\\classes\\audio\\【排骨x西瓜JUN】锦鲤抄【原创PV付】.m4a").toURI().toString());
        Media media = new Media(PROXY_URL + autoUrl);
//        Media media = new Media("http://localhost:8023/music/zhulinjian.m4a");
        System.out.println(PROXY_URL + autoUrl);
        this.player = new MediaPlayer(media);
        this.player.play();
        playing.set(true);
//        绑定音量
        this.player.volumeProperty().bind(volumeSlider.valueProperty().divide(volumeSlider.maxProperty()));
        //        故障后播放下一首
        this.player.errorProperty().addListener((observable, oldValue, newValue) -> {
            newValue.printStackTrace();
            nextMedia(null);
        });
//        播放完成后播放下一首
        this.player.setOnEndOfMedia(() -> {
            nextMedia(null);
        });
        this.player.setOnReady(() -> {
            progressSlider.setValue(0);
            progressSlider.setMin(0);
            progressSlider.setMax(this.player.getTotalDuration().toSeconds());
//            进度条跟着走
            this.player.currentTimeProperty().addListener((observable, oldValue, newValue) -> {
                if (!onPressMouse) {
                    this.progressSlider.setValue(newValue.toSeconds());
                }
            });
        });
    }

    public void playMedia(ActionEvent actionEvent) {
        if (player == null) {
            Platform.runLater(this::play);
            return;
        }
        if (playing.get()) {
            player.pause();
        } else {
            player.play();
        }
        Platform.runLater(() -> playing.set(!playing.getValue()));
    }


    public void prevMedia(ActionEvent actionEvent) {
        if (listIndex > 0) {
            listIndex--;
        } else {
            listIndex = mTable.getItems().size() - 1;
        }
        play();
    }

    public void nextMedia(ActionEvent actionEvent) {
        switch (selectPlayModel) {
            case LOOP:
                if (listIndex < mTable.getItems().size() - 1) {
                    listIndex++;
                } else {
                    listIndex = 0;
                }
                break;
            case RANDOM:
                if (randomIndex.size() == 0) {
                    initRandom();
                }
                listIndex = randomIndex.remove(0);
                break;

        }
        play();
    }

    public void doRefresh(ActionEvent actionEvent) {
        loadList();
    }
}
